package com.example.blog.modules.article.service.impl;

import com.example.blog.common.exception.ServiceException;
import com.example.blog.modules.article.dto.TagDTO;
import com.example.blog.modules.article.entity.Tag;
import com.example.blog.modules.article.repository.TagRepository;
import com.example.blog.modules.article.service.TagService;
import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class TagServiceImpl implements TagService {

    private final TagRepository tagRepository;

    @Override
    @Transactional
    public TagDTO createTag(TagDTO tagDTO) {
        if (tagRepository.existsByName(tagDTO.getName())) {
            throw new ServiceException("标签名称已存在");
        }
        
        Tag tag = new Tag();
        updateTagFromDTO(tag, tagDTO);
        return convertToDTO(tagRepository.save(tag));
    }

    @Override
    @Transactional
    public TagDTO updateTag(Long id, TagDTO tagDTO) {
        Tag tag = tagRepository.findById(id)
                .orElseThrow(() -> new ServiceException("标签不存在"));
        
        if (!tag.getName().equals(tagDTO.getName()) && 
            tagRepository.existsByName(tagDTO.getName())) {
            throw new ServiceException("标签名称已存在");
        }
        
        updateTagFromDTO(tag, tagDTO);
        return convertToDTO(tagRepository.save(tag));
    }

    @Override
    @Transactional
    public void deleteTag(Long id) {
        Tag tag = tagRepository.findById(id)
                .orElseThrow(() -> new ServiceException("标签不存在"));
        
        if (!tag.getArticles().isEmpty()) {
            throw new ServiceException("该标签下还有文章，无法删除");
        }
        
        tagRepository.delete(tag);
    }

    @Override
    @Transactional(readOnly = true)
    public TagDTO getTag(Long id) {
        return convertToDTO(tagRepository.findById(id)
                .orElseThrow(() -> new ServiceException("标签不存在")));
    }

    @Override
    @Transactional(readOnly = true)
    public List<TagDTO> getAllTags() {
        return tagRepository.findAllByOrderBySortAsc()
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public List<TagDTO> getTagsByIds(Set<Long> ids) {
        return tagRepository.findByIdIn(ids)
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public Page<TagDTO> getTags(String keyword, Pageable pageable) {
        Specification<Tag> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            if (StringUtils.hasText(keyword)) {
                predicates.add(criteriaBuilder.or(
                    criteriaBuilder.like(root.get("name"), "%" + keyword + "%"),
                    criteriaBuilder.like(root.get("description"), "%" + keyword + "%")
                ));
            }
            
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
        
        return tagRepository.findAll(spec, pageable).map(this::convertToDTO);
    }

    private void updateTagFromDTO(Tag tag, TagDTO dto) {
        tag.setName(dto.getName());
        tag.setDescription(dto.getDescription());
        tag.setSort(dto.getSort() != null ? dto.getSort() : 0);
    }

    private TagDTO convertToDTO(Tag tag) {
        TagDTO dto = new TagDTO();
        dto.setId(tag.getId());
        dto.setName(tag.getName());
        dto.setDescription(tag.getDescription());
        dto.setSort(tag.getSort());
        dto.setArticleCount(tag.getArticles().size());
        dto.setCreateTime(tag.getCreateTime());
        dto.setUpdateTime(tag.getUpdateTime());
        return dto;
    }
} 